/** @file oct_node.cpp
    @brief Octree node */

#include "oct/oct_node.h"

using namespace G3;

//==============================================================================
// Constructor(s)
//==============================================================================
G3::OCT_NODE::OCT_NODE () {
    for (int i=0; i<8; i++)
        children [i] = 0;

    node_vis_cache = G3::GFC_OUT;

    log = &G3::MainLog;
}

//==============================================================================
// A copy-constructor
//==============================================================================
G3::OCT_NODE::OCT_NODE (const OCT_NODE &node) {
    BBox = node.BBox;

    for (int i=0; i<8; i++)
        children [i] = node.children [i];

    node_vis_cache = node.node_vis_cache;

    log = node.log;
}

//==============================================================================
// Destructor(s)
//==============================================================================
G3::OCT_NODE::~OCT_NODE () {
    clear ();
}

//==============================================================================
// Assignment operator
//==============================================================================
G3::OCT_NODE &G3::OCT_NODE::operator= (const G3::OCT_NODE &node) {
    BBox = node.BBox;

    for (int i=0; i<8; i++)
        children [i] = node.children [i];

    node_vis_cache = node.node_vis_cache;

    log = node.log;

    return *this;
}

//==============================================================================
// Clears the node
//==============================================================================
void G3::OCT_NODE::clear () {
    for (int i=0; i<8; i++)
        children [i] = 0;
}

//==============================================================================
// Dumps the node
//==============================================================================
void G3::OCT_NODE::dump () {
    if (log) {
        log->Report ("Children: ");

        for (int i=0; i<8; i++)
            log->Report ("%d ", children [i]);

        log->Report ("\nBBox: (%f, %f, %f) (%f, %f, %f)\n",
            BBox.Minimum.x, BBox.Minimum.y, BBox.Minimum.z, BBox.Maximum.x, BBox.Maximum.y, BBox.Maximum.z);

        log->Report ("Visibility cache: %d\n", node_vis_cache);
    }
}

int G3::OCT_NODE::upload (const std::vector<G3::OCT_NODE> &nodes, const std::vector<G3::OCT_LEAF> &leaves, std::vector<G3::BATCH> &batches, const G3::VEC3F &pos) const {
    std::list<int> nodelist;
    std::list<int>::iterator it;
    int i, num = 0;

    for (i=0; i<8; i++) {
        if (children [i] == 0 || (children [i] - 1 > (int) nodes.size ()) ||
            (-children [i] - 1 > (int) leaves.size ()))
            continue;

        nodelist.push_back (children [i]);
    }

    while (!nodelist.empty ()) {
        it = nodelist.begin ();

        if (*it > 0)
            num += nodes [*it - 1].upload (nodes, leaves, batches, pos);
        else
            num += leaves [-(*it) - 1].upload (batches, pos);

        nodelist.pop_front ();
    }

    return num;
}

int G3::OCT_NODE::upload_removal (const std::vector<G3::OCT_NODE> &nodes, const std::vector<G3::OCT_LEAF> &leaves, std::vector<G3::BATCH> &batches) const {
    std::list<int> nodelist;
    std::list<int>::iterator it;
    int i, num = 0;

    for (i=0; i<8; i++) {
        if (children [i] == 0 || (children [i] - 1 > (int) nodes.size ()) ||
            (-children [i] - 1 > (int) leaves.size ()))
            continue;

        nodelist.push_back (children [i]);
    }

    while (!nodelist.empty ()) {
        it = nodelist.begin ();

        if (*it > 0)
            num += nodes [*it - 1].upload_removal (nodes, leaves, batches);
        else
            num += leaves [-(*it) - 1].upload_removal (batches);

        nodelist.pop_front ();
    }

    return num;
}
